package org.ccay.enumerable.loader;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

import com.opensymphony.xwork2.util.logging.Logger;

import org.ccay.enumerable.EnumItem;
import org.ccay.enumerable.exception.MappingException;

/**
 * java枚举类方式加载字典项
 * @author chaowangbang
 *
 */
public class JavaEnumLoader implements EnumLoader{

	private static final String RESOURCE_PATTERN = "/**/*.class";
	
	private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

	private String[] packagesToScan;
	
	public void setPackagesToScan(String... packagesToScan) {
		this.packagesToScan = packagesToScan;
	}
	
	private List<Class<?>> enumClasses = new ArrayList<Class<?>>();
	
	public JavaEnumLoader(){};
	
	public JavaEnumLoader(String ... packagesToScan){
		this.packagesToScan = packagesToScan;
	}
	
	@Override
	public Map<String, List<EnumItem>> load() {
		Map<String, List<EnumItem>> result = new HashMap<String, List<EnumItem>>();
		for (Class<?> clazz :  getEnumClasses()) {
			if (clazz.isEnum()) {
				Method method = null;
				EnumItem[] enums = null;
				try {
					method = clazz.getMethod("values");
					enums = (EnumItem[]) method.invoke(null, null);
				} catch (NoSuchMethodException e1) {
					e1.printStackTrace();
				} catch (SecurityException e1) {
					e1.printStackTrace();
				} catch (IllegalAccessException e1) {
					e1.printStackTrace();
				} catch (IllegalArgumentException e1) {
					e1.printStackTrace();
				} catch (InvocationTargetException e1) {
					e1.printStackTrace();
				}
				for (EnumItem e : enums) {
					String key = e.getType();
					if (!result.containsKey(key)) {
						result.put(key, new ArrayList<EnumItem>());
					} 
					List<EnumItem> ets = result.get(key);
					ets.add(e);
				}
			}
		}
		return result;
	}
	private boolean isImplementEnumItemInterface(Class<?> clazz){
		for(Class<?> face : clazz.getInterfaces()){
			if(face.equals(EnumItem.class)){
				return true;
			}
		}
		return false;
		
	};
	public void initEnumClass(){
		try {
			for (String pkg : this.packagesToScan) {
				String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
						ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;
				Resource[] resources = this.resourcePatternResolver.getResources(pattern);
				MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
				for (Resource resource : resources) {
					if (resource.isReadable()) {
						MetadataReader reader = readerFactory.getMetadataReader(resource);
						String className = reader.getClassMetadata().getClassName();
						Class<?> clazz = resourcePatternResolver.getClassLoader().loadClass(className);
						clazz.getInterfaces();
						//clazz.isAssignableFrom(EnumItem.class))对枚举类型貌似判断失效！！
						if(clazz.isEnum() && isImplementEnumItemInterface(clazz)){
							enumClasses.add(clazz);
						}
					}
				}
			}
		}
		catch (IOException ex) {
			throw new MappingException("Failed to scan classpath for unlisted classes", ex);
		}
		catch (ClassNotFoundException ex) {
			throw new MappingException("Failed to load annotated classes from classpath", ex);
		}
	}

	synchronized public List<Class<?>> getEnumClasses() {
		if(enumClasses.isEmpty()){
			initEnumClass();
		}
		return enumClasses;
	}
}
